<?php
/**
 * 应用（Application）模型
 * 
 * ============================================================================
 * 版权所有: (c) 2009-2011，<UEShop Inc>，并保留所有权利。
 * 网站地址: http://www.ueshop.cn
 * ----------------------------------------------------------------------------
 * 这不是一个自由软件！您只能在不用于商业目的的前提下对程序代码进行修改和使用；
 * 不允许对程序代码以任何形式任何目的的再发布。
 * ============================================================================
 * @author cmpan
 * @copyright   Copyright (c) 2009-2011 UEShop Inc. (http://www.ueshop.cn)
 * @license     http://www.ueshop.cn/1_0.txt
 */
class AppModel extends UE_Model {
	public $key    = 'app_id';
	public $table  = 'ue_app';
	public $id     = '';
	
	/**
	 * 清除apps信息
	 * 
	 * 把apps相关信息缓存删除，
	 * 读取到该数据的时候，如果缓存不存在将会重新生成该缓存
	 */
	public function clearAppsCache() {
		$cache = UE_Cache::createCache();
		$cache->delete('apps');
		$cache->delete('acls');
		$cache->delete('acts');
	}

	/**
	 * 获取应用的信息
	 * 
	 * 应用信息格式为：<pre>
	 * $INFO = array(
	 *     'app_name'          => 'app名',
	 *     'app_version'       => 'app版本',
	 *     'app_author'        => 'app作者',
	 *     'app_contact'       => 'app作者联系方式', //2
	 *     'app_sitename'      => 'app主页', //3
	 *     'app_siteurl'       => 'app主页', // 4
	 *	   'app_package'       => 'app类型', // core|option|other (核心包|可选包|其他)
	 *     'app_desc'          => 'app描述信息', 
	 *     'app_activated'     => '',
	 * );</pre>
	 *
	 * @param string $app
	 * @return array
	 */
	public function getInfo($appId) {
		$apps = self::getApps();
		
		if (!empty($apps[$appId])) {
			return $apps[$appId];
		}
		
		$infoFile = APPS_DIR."/$appId/info.php";
		if (!is_file($infoFile)) {
			return array (
				'app_name'       => '',
				'app_version'    => '<span class="red">—</span> ',
				'app_author'     => '<span class="red">—</span> ',
				'app_contact'    => '',
				'app_sitename'   => '',
				'app_siteurl'    => '',
				'app_desc'       => '<font color=red>错误：应用信息不存在</font>',
			    'app_package'    => 'other',
			    'app_err'        => '（'.$infoFile.'）信息文件不存在',
			    'app_installed'  => 0,
			    'app_activated'  => 0,
			);
		} else {
			$info = include $infoFile;
			// 验证$appInfo
			if(empty($info)) {
			    $info['app_err'] = '应用配置信息文件中没有配置信息';
			}

		    if(empty($info['app_name'])) {
				$info['app_name'] = '<b class="red">没有配置信息名</b>';
		    }
		    
		    if(empty($info['app_desc'])) {
				$info['app_desc'] = '<span class="red">' . (empty($info['app_err']) ? '配置文件格式错误' : $info['app_err']) . '</span>';
		    }
		    
		    if (!empty($info['app_contact']) && UE_Validate::isEmail($info['app_contact'])) {
	    		$info['app_contact'] = 'mailto:'.$info['app_contact'];
	    	} 
	    	
	    	 if (empty($info['app_author'])) {
	    		$info['app_author'] = ' <span class="red">—</span> ';
	    	} 
	    	
	    	if (empty($info['app_version'])) {
	    		$info['app_version'] = ' <span class="red">—</span> ';
	    	}
	    	
		    $info['app_installed']      = 0;
		    $info['app_activated']      = 0;
		    
			return $info;
		}
	}
	
	/**
	 * 读取应用的action.php中的配置信息
	 *
	 * @param string $app
	 * @return array
	 */
	public function getAppActionsInfo($app) {		
		$actsInfoFile = APPS_DIR . "/$app/actions.php";
		if (!is_file($actsInfoFile)) {
			return array ();
		} else {
			return include $actsInfoFile;
		}
	}
	
	/**
	 * 安装应用
	 *
	 * @param string $appId
	 * @return bool
	 */
	public function install($appId) {
		$appInfo = $this->getInfo($appId);
		$apps = $this->getApps();
		
		if (isset($apps[$appId])) {
			$this->setErr('该应用（'.$appId.'）已经安装好了，不能重复安装应用。');
			return false;
		}
				
		if (isset($appInfo['app_err'])) {
			$this->setErr($appInfo['app_err']);
			return false;
		}
		
		empty($appInfo['package']) && $appInfo['package'] = 'other';

		// 把当前安装应用的信息添加到 $apps 变量中
		$appInfo['app_activated']    = 1;
		$appInfo['app_id']           = $appId;
		$apps[$appId]                = $appInfo;
		//print_r($appInfo);
		
		$appInfo['install_time'] = time();
		$appInfo['install_uid']  = $_SESSION['user_id'];
		 
		
		UE_DB::factory()->insertRow($this->table, array_map('addslashes', $appInfo));
		
		// 创建表 TODO
		
		// 读取actions文件信息
		$appActionsInfo = $this->getAppActionsInfo($appId);
		empty($appActionsInfo['actions']) && $appActionsInfo['actions'] = array();
		empty($appActionsInfo['acl']) && $appActionsInfo['acl'] = array();
		empty($appActionsInfo['admin_menu']) && $appActionsInfo['admin_menu'] = array();

		// 将应用actions添加到actions列表中
		foreach ($appActionsInfo['actions'] as $actCtl => $actList) {
			foreach ($actList as $actId => $actName) {
				$this->addAction($appId, $actCtl, $actId, $actName);
			}
		}
		
		UE_Loader::loadModel('RoleModel', 'user');
		$role = new RoleModel();
		$roles = $role->getRoles('', false);		
		// 将应用权限控制设置添加到权限控制列表中
		foreach ($appActionsInfo['acl'] as $aclCtl => $actList) {
			foreach ($actList as $actId => $aclList) {
				//print_r($roles);
				foreach ($roles as $roleItem) {
					if ($roleItem['role_type'] == 'admin') {
						$access = $aclList[0];
					} elseif ($roleItem['role_type'] == 'member') {
						$access = $aclList[1];
					} else {
						$access = $aclList[2];
					}
					
					// 把有权限访问的配置添加到权限控制列表
				    $access && $this->addAcl($appId, $aclCtl, $actId, $roleItem['role_id'], $access);
				    $roleItem = array();			    
				}
			}
		}
		
		// 后台菜单
		UE_Loader::loadModel('MenuModel', 'system');
		
		$menuModel = new MenuModel();
		foreach ($appActionsInfo['admin_menu'] as $adminMenuKey => $adminMenuVal) {
			$menuItem = array();
			$menuItem['menu_parent_id'] = $adminMenuVal[0];
			$menuItem['menu_name'] = $adminMenuVal[1];
			list($menuApp, $menuCtl, $menuAct) = explode('/', $adminMenuKey);
			$menuItem['menu_app'] = $menuApp;
			$menuItem['menu_ctl'] = $menuCtl;
			$menuItem['menu_act'] = $menuAct;
			// 测试时关闭
			//$menuModel->add($menuItem);
		}

		// 清除应用相关缓存
		$this->clearAppsCache($apps);
		
		return true;
	}
	
	/**
	 * 启用应用
	 *
	 * @param string $appId
	 */
	public function activate($appId) {
		$apps = $this->getApps();
		
		if(empty($apps[$appId])) {
			$this->setErr('该应用（'.$appId.'尚未安装。');
			return false;
		}
		
		$sql = "UPDATE $this->table SET app_activated = 1 WHERE app_id='$appId'";
		UE_DB::factory()->query($sql);
		
		$this->clearAppsCache();
		
		return true;
	}
	
	
	/**
	 * 停用应用
	 *
	 * @param string $appId
	 * @return bool
	 */
	public function deactivate($appId) {
		$appInfo = $this->getInfo($appId);
		$apps = $this->getApps();
		
		if (empty($apps[$appId])) {
			$this->setErr('该应用（'.$appId.'）尚未启用，不能被停用。');
			return false;
		}
		
		// TODO不允许停用核心模块
		if ($appInfo['app_package'] == 'core') {
			$this->setErr('核心应用（'.$appId.'）不能被停用。');
			//return false;
		}
		
		$sql = "UPDATE $this->table SET app_activated = 0 WHERE app_id='$appId'";
		UE_DB::factory()->query($sql);
		
		$this->clearAppsCache();
				
		return true;
	}
	
	/**
	 * 卸载应用，之后再控制器中清除缓存
	 *
	 * @param string $appId
	 * @return bool
	 */
	public function uninstall($appId) {	
		$apps = $this->getApps();
		
		if (empty($apps[$appId])) {
			$this->setErr('该应用（'.$appId.'）尚未启用，不能被卸载。');
			return false;
		}
		
		//$appInfo = $this->getInfo($appId);
		$appInfo = $apps[$appId];
		
		// TODO不允许卸载核心模块
		if ($appInfo['app_package'] == 'core') {
			//$this->setErr('核心应用（'.$appId.'）不能被卸载。');
			//return false;
		}		
		
		// 删除表 TODO
		
		// 删除应用信息
		UE_DB::factory()->query("DELETE FROM ue_app WHERE app_id='$appId'");
		
		// 删除应用功能列表
		UE_DB::factory()->query("DELETE FROM ue_act WHERE act_app='$appId'");
		
		// 删除应用权限控制列表
		UE_DB::factory()->query("DELETE FROM ue_acl WHERE acl_app='$appId'");
		
		// 后台菜单设置
		// 测试时关闭
		//UE_DB::factory()->query("DELETE FROM ue_menu WHERE menu_app='$appId'");
				
		
		$this->clearAppsCache($apps);
		
		return true;
	}
	
	/**
	 * 获取已安装应用的信息
	 *
	 * @return array
	 */
	public static function getApps() {
		$cache = UE_Cache::createCache();
		if (!$apps = $cache->get('apps', false)) {		
			$apps = array();
			$tmp = self::_db()->getAll("SELECT * FROM ue_app");
			if ($tmp) {
				foreach ($tmp as $app) {
					$app['app_installed'] = 1;
					$apps[$app['app_id']] = $app;
				}
			}
			
			$cache->set('apps', $apps);
		}
		
		return $apps;
	}	
	
	/**
	 * 删除应用的所有文件
	 *
	 * @param string $appId
	 */
	public function delete($appId) {
		$apps = $this->getApps();		
		$appInfo = $this->getInfo($appId);
		
		// TODO不允许卸载核心模块
		if (!empty($appInfo['app_package']) && $appInfo['app_package'] == 'core') {
			$this->setErr('核心应用（'.$appId.'）不能被删除。');
			return false;
		}
		
		if (!empty($apps[$appId])) {
			$this->setErr('该应用（'.$appId.'）尚未卸载，不能被删除。');
			return false;
		}
		
		// 删除文件
		realRemoveDir(APPS_DIR.'/'.$appId);
		
		$this->clearAppsCache($apps);
		
		return true;
	}
	
	/**
	 * 添加一个action
	 * 
	 *
	 * @param string $app
	 * @param string $ctl
	 * @param string $act
	 * @param string $name
	 * @return int
	 */
	public function addAction($app, $ctl, $act, $name) {
		$name = addslashes($name);
		$db = UE_DB::factory();
		
		$sql = "REPLACE INTO ue_act (act_name, act_app, act_ctl, act_act) VALUE ('$name', '$app', '$ctl', '$act')";
		$r = UE_DB::factory()->query($sql);
		
		// 删除acts缓存
		@unlink(DATA_DIR.'/system/acts.php');
		return $r;
	}
	
	/**
	 * 添加权限控制列表的时候，都是把旧的控制列表删除再添加新的，因此不必验证是否已经添加该权限配置
	 *
	 * @param string $app
	 * @param string $ctl
	 * @param string $act
	 * @param int $roleId
	 * @param bool $access
	 * @return int
	 */
	public function addAcl($app, $ctl, $act, $roleId, $access) {
		$db = UE_DB::factory();
		$sql = "REPLACE INTO ue_acl (acl_role_id, acl_app, acl_ctl, acl_act, acl_access) 
			                     VALUE ('$roleId', '$app', '$ctl', '$act', '$access')";
		$r = $db->query($sql);
		
		// 删除acls缓存
		@unlink(DATA_DIR.'/system/acls.php');
		return $r;
	}
	
	/**
	 * 获取权限控制列表
	 *
	 * @param string $app
	 * @return array
	 */
	public static function getAcls($app = '') {
		$cache = UE_Cache::createCache();
		
		if (!$acls = $cache->get('acls', false)) {		
			$sql = "SELECT * FROM ue_acl ORDER BY acl_app, acl_ctl";			
			$rs = UE_DB::factory()->getAll($sql);
			
			$acls = array();			
			foreach ($rs as $r) {
				$acls[$r['acl_app']][$r['acl_ctl']][$r['acl_act']][$r['acl_role_id']] = $r['acl_access'];
			}
			
			$cache->set('acls', $acls);			
		}
			
		return $app ? (empty($acls[$app]) ? array() : $acls[$app]) : $acls;
	}
	
	/**
	 * 获取所有action
	 *
	 * @param string $app
	 * @return array
	 */
	public static function getActs($app = '') {
		$cache = UE_Cache::createCache();
		
		if (!$acts = $cache->get('acts', false)) {
			// 取得所有 actions
			$sql = "SELECT * FROM ue_act ORDER BY act_app";			
			$rs = UE_DB::factory()->getAll($sql);
			
			$acts = array();
			foreach ($rs as $r) {
				$acts[$r['act_app']][$r['act_ctl']][$r['act_act']] = $r['act_name'];			
			}
			
			$cache->set('acts', $acts);
		}
		
		//
		return $app ? (empty($acts[$app]) ? array() : $acts[$app]) : $acts;
	}
	
	/**
	 * 功能是否能访问
	 *
	 * @param string $app
	 * @param string $ctl
	 * @param string $act
	 * @param int &$errCode  403|404 403=没有权限 404=页面不存在
	 * @return bool
	 */
	public static function isActionAcessable($app, $ctl, $act, &$errCode = 0) {
		if (empty($app) || empty($ctl) || empty($act)) {
			$errCode = 404;
			return false;
		}
		
		$appActs = self::getActs($app);
		$appAcls = self::getAcls($app);
		$appInfo = self::getInfo($app);
		
		// app未安装或已经被禁用已经被禁用
		if (empty($appInfo['app_activated'])) {
			$errCode = 404;
			return false;
		}
		
		// 如果action不存在
		if (empty($appActs[$ctl][$act])) {
			$errCode = 404;
			return false;
		}
				
		// 超级管理员
		if ($_SESSION['user_type'] == 'super') {
			return true;
		}
		
		$access = false;
		$actAcls = empty($appAcls[$ctl][$act]) ? array() : $appAcls[$ctl][$act];
		
		// 管理员的访问权限
		if ($_SESSION['user_type'] == 'admin') {
			$userRoles = array();
			// 如果该管理员没有设置权限，则使用所有会员组的权限和
			if (empty($_SESSION['user_role'])) {
				$roleModel = new RoleModel();
				$memberRoles = $roleModel->getRoles('member', false);
				if ($memberRoles) {
					foreach ($memberRoles as $r) {
						$userRoles[] = $r['role_id'];
					}
				}
			} else {
			    $userRoles = explode(',', $_SESSION['user_role']);
			}
			
			for ($i = 0; $i < count($userRoles); $i++) {
				$access = !empty($actAcls[$userRoles[$i]]);
				if ($access) {
					break;
				}
			}			
		} else {
		    // 其他非管理员用户权限
		    $access = !empty($actAcls[$_SESSION['user_role']]);
		}
		
		if ($access) {	
			return true;
		}
		
		// 没有权限
		$errCode = 403;
		return false;
	}

}
